const crypto = require('crypto');
const fs = require('fs');

const { Certificate, PrivateKey } = require('@fidm/x509');

// 退款通知解密key=md5(key)
function decryptData (encryptedData, key, iv = '') {
  // 解密
  const decipher = crypto.createDecipheriv('aes-256-ecb', key, iv)
  // 设置自动 padding 为 true，删除填充补位
  decipher.setAutoPadding(true)
  let decoded = decipher.update(encryptedData, 'base64', 'utf8')
  decoded += decipher.final('utf8')
  return decoded
}

function md5 (str, encoding = 'utf8') {
  return crypto
    .createHash('md5')
    .update(str, encoding)
    .digest('hex')
}

function sha256 (str, key, encoding = 'utf8') {
  return crypto
    .createHmac('sha256', key)
    .update(str, encoding)
    .digest('hex')
}

function getNonceStr (length = 16) {
  let str = ''
  while (str.length < length) {
    str += Math.random().toString(32).substring(2)
  }
  return str.substring(0, length)
}

function loadCertFromPath (filePath) {
  return Certificate.fromPEM(fs.readFileSync(filePath))
}

function loadCertFromContent (content) {
  if (typeof content === 'string') content = Buffer.from(content)
  return Certificate.fromPEM(content)
}

function loadPrivateKeyFromPath (filePath) {
  return PrivateKey.fromPEM(fs.readFileSync(filePath))
}

function loadPrivateKeyFromContent (content) {
  if (typeof content === 'string') content = Buffer.from(content)
  return PrivateKey.fromPEM(content)
}

function decodeBase64 (str) {
  return Buffer.from(str, 'base64').toString('utf-8')
}

function decryptCiphertext (ciphertext, key, nonce, associatedData) {
  const encryptData = Buffer.from(ciphertext, 'base64')
  const decipher = crypto.createDecipheriv('aes-256-gcm', key, nonce)

  decipher.setAuthTag(encryptData.slice(-16))
  decipher.setAAD(Buffer.from(associatedData))

  const result = Buffer.concat([
    decipher.update(encryptData.slice(0, -16)),
    decipher.final()
  ])

  return result.toString()
}

/**
 * 使用私钥创建 RSA-SHA256 签名
 * @param {String} privateKey 私钥
 * @param {String} str 签名字符串
 * @param {HexBase64Latin1Encoding} format=base64 签名格式
 * @returns {Buffer}
 */
function rsaPrivateKeySign (privateKey, str, format = 'base64') {
  return crypto.createSign('RSA-SHA256').update(Buffer.from(str), 'utf8').sign(privateKey)
}
/**
 * 使用 RSA 公钥加密数据
 * @param {String} data 数据
 * @param {String} publicKey 公钥
 */
function rsaPublicKeyEncryptData (data, publicKey) {
  return crypto.publicEncrypt({
    key: publicKey,
    padding: crypto.constants.RSA_PKCS1_OAEP_PADDING
  }, Buffer.from(data))
}
/**
 * 使用 RSA 私钥解密数据
 * @param {String|Buffer} encryptData 数据
 * @param {String} privateKey 私钥
 */
function rsaPrivateKeyDecryptData (encryptData, privateKey) {
  if (typeof encryptData === 'string') encryptData = Buffer.from(encryptData)

  const decrypted = crypto.privateDecrypt({
    key: privateKey,
    padding: crypto.constants.RSA_PKCS1_OAEP_PADDING
  }, encryptData)
  return decrypted.toString()
}

function rsaPublicKeyVerifySign (publicKey, str, sign) {
  return crypto.createVerify('RSA-SHA256').update(str, 'utf8').verify(publicKey, sign, 'base64')
}

function getQueryStr (obj) {
  return Object.keys(obj)
    .map(key => key + '=' + obj[key])
    .join('&')
}
function formatKey (key, type) {
  return `-----BEGIN ${type}-----\n${key}\n-----END ${type}-----`
}

module.exports = {
  decryptData,
  md5,
  sha256,
  getQueryStr,
  getNonceStr,
  decodeBase64,
  decryptCiphertext,
  loadCertFromPath,
  loadCertFromContent,
  loadPrivateKeyFromPath,
  loadPrivateKeyFromContent,
  rsaPrivateKeySign,
  rsaPublicKeyVerifySign,
  rsaPublicKeyEncryptData,
  rsaPrivateKeyDecryptData,
  formatKey
}